home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Sample.bin / SpreadSheet.java < prev    next >
Text File  |  1998-09-15  |  22KB  |  925 lines

  1. /*
  2.  * @(#)SpreadSheet.java    1.6 97/07/30
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
  7.  * modify and redistribute this software in source and binary code form,
  8.  * provided that i) this copyright notice and license appear on all copies of
  9.  * the software; and ii) Licensee does not utilize the software in a manner
  10.  * which is disparaging to Sun.
  11.  *
  12.  * This software is provided "AS IS," without a warranty of any kind. ALL
  13.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  14.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  15.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  16.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  17.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  18.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  19.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  20.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  21.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  22.  * POSSIBILITY OF SUCH DAMAGES.
  23.  *
  24.  * This software is not designed or intended for use in on-line control of
  25.  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
  26.  * the design, construction, operation or maintenance of any nuclear
  27.  * facility. Licensee represents and warrants that it will not use or
  28.  * redistribute the Software for such purposes.
  29.  */
  30.  
  31. import java.applet.Applet;
  32. import java.awt.*;
  33. import java.awt.event.*;
  34. import java.io.*;
  35. import java.lang.*;
  36. import java.net.*;
  37.  
  38. public class SpreadSheet 
  39.     extends Applet
  40.     implements MouseListener, KeyListener {
  41.     String        title;
  42.     Font        titleFont;
  43.     Color        cellColor;
  44.     Color        inputColor;
  45.     int            cellWidth = 100;
  46.     int            cellHeight = 15;
  47.     int            titleHeight = 15;
  48.     int            rowLabelWidth = 15;
  49.     Font        inputFont;
  50.     boolean        isStopped = false;
  51.     boolean        fullUpdate = true;
  52.     int            rows;
  53.     int            columns;
  54.     int            currentKey = -1;
  55.     int            selectedRow = -1;
  56.     int            selectedColumn = -1;
  57.     SpreadSheetInput    inputArea;
  58.     Cell        cells[][];
  59.     Cell        current = null;
  60.  
  61.     public synchronized void init() {
  62.     String rs;
  63.     
  64.     cellColor = Color.white;
  65.     inputColor = new Color(100, 100, 225);
  66.     inputFont = new Font("Courier", Font.PLAIN, 10);
  67.     titleFont = new Font("Courier", Font.BOLD, 12);
  68.     title = getParameter("title");
  69.     if (title == null) {
  70.         title = "Spreadsheet";
  71.     }
  72.     rs = getParameter("rows");
  73.     if (rs == null) {
  74.         rows = 9;
  75.     } else {
  76.         rows = Integer.parseInt(rs);
  77.     }
  78.     rs = getParameter("columns");
  79.     if (rs == null) {
  80.         columns = 5;
  81.     } else {
  82.         columns = Integer.parseInt(rs);
  83.     }
  84.     cells = new Cell[rows][columns];
  85.     char l[] = new char[1];
  86.     for (int i=0; i < rows; i++) {
  87.         for (int j=0; j < columns; j++) {
  88.  
  89.         cells[i][j] = new Cell(this,
  90.                        Color.lightGray,
  91.                        Color.black,
  92.                        cellColor,
  93.                        cellWidth - 2,
  94.                        cellHeight - 2);
  95.         l[0] = (char)((int)'a' + j);
  96.         rs = getParameter("" + new String(l) + (i+1));
  97.         if (rs != null) {
  98.             cells[i][j].setUnparsedValue(rs);
  99.         }
  100.         }
  101.     }
  102.  
  103.     Dimension d = getSize();
  104.     inputArea = new SpreadSheetInput(null, this, d.width - 2, cellHeight - 1,
  105.                      inputColor, Color.white);
  106.     resize(columns * cellWidth + rowLabelWidth,
  107.            (rows + 3) * cellHeight + titleHeight);
  108.     addMouseListener(this);
  109.     addKeyListener(this);
  110.     }
  111.  
  112.     public void setCurrentValue(float val) {
  113.     if (selectedRow == -1 || selectedColumn == -1) {
  114.         return;
  115.     }
  116.     cells[selectedRow][selectedColumn].setValue(val);
  117.     repaint();
  118.     }
  119.  
  120.     public void stop() {
  121.     isStopped = true;
  122.     }
  123.  
  124.     public void start() {
  125.     isStopped = false;
  126.     }
  127.  
  128.     public void destroy() {
  129.     for (int i=0; i < rows; i++) {
  130.         for (int j=0; j < columns; j++) {
  131.         if (cells[i][j].type == Cell.URL) {
  132.             cells[i][j].updaterThread.stop();
  133.         }
  134.         }
  135.     }
  136.     }
  137.  
  138.     public void setCurrentValue(int type, String val) {
  139.     if (selectedRow == -1 || selectedColumn == -1) {
  140.         return;
  141.     }
  142.     cells[selectedRow][selectedColumn].setValue(type, val);
  143.     repaint();
  144.     }
  145.  
  146.     public void update(Graphics g) {
  147.     if (! fullUpdate) {
  148.         int cx, cy;
  149.  
  150.         g.setFont(titleFont);
  151.         for (int i=0; i < rows; i++) {
  152.         for (int j=0; j < columns; j++) {
  153.             if (cells[i][j].needRedisplay) {
  154.             cx = (j * cellWidth) + 2 + rowLabelWidth;
  155.             cy = ((i+1) * cellHeight) + 2 + titleHeight;
  156.             cells[i][j].paint(g, cx, cy);
  157.             }
  158.         }
  159.         }
  160.     } else {
  161.         paint(g);
  162.         fullUpdate = false;
  163.     }
  164.     }
  165.  
  166.     public void recalculate() {
  167.     int    i,j;
  168.  
  169.     //System.out.println("SpreadSheet.recalculate");
  170.     for (i=0; i < rows; i++) {
  171.         for (j=0; j < columns; j++) {
  172.         if (cells[i][j] != null && cells[i][j].type == Cell.FORMULA) {
  173.             cells[i][j].setRawValue(evaluateFormula(cells[i][j].parseRoot));
  174.             cells[i][j].needRedisplay = true;
  175.         }
  176.         }
  177.     }
  178.     repaint();
  179.     }
  180.  
  181.     public float evaluateFormula(Node n) {
  182.     float    val = 0.0f;
  183.  
  184.     //System.out.println("evaluateFormula:");
  185.     //n.print(3);
  186.     if (n == null) {
  187.         //System.out.println("Null node");
  188.         return val;
  189.     }
  190.     switch (n.type) {
  191.       case Node.OP:
  192.         val = evaluateFormula(n.left);
  193.         switch (n.op) {
  194.           case '+':
  195.         val += evaluateFormula(n.right);
  196.         break;
  197.           case '*':
  198.         val *= evaluateFormula(n.right);
  199.         break;
  200.           case '-':
  201.         val -= evaluateFormula(n.right);
  202.         break;
  203.           case '/':
  204.         val /= evaluateFormula(n.right);
  205.         break;
  206.         }
  207.         break;
  208.       case Node.VALUE:
  209.         //System.out.println("=>" + n.value);
  210.         return n.value;
  211.       case Node.CELL:
  212.         if (n == null) {
  213.         //System.out.println("NULL at 192");
  214.         } else {
  215.         if (cells[n.row][n.column] == null) {
  216.             //System.out.println("NULL at 193");
  217.         } else {
  218.             //System.out.println("=>" + cells[n.row][n.column].value);
  219.             return cells[n.row][n.column].value;
  220.         }
  221.         }
  222.     }
  223.  
  224.     //System.out.println("=>" + val);
  225.     return val;
  226.     }
  227.  
  228.     public synchronized void paint(Graphics g) {
  229.     int i, j;
  230.     int cx, cy;
  231.     char l[] = new char[1];
  232.  
  233.  
  234.     Dimension d = getSize();
  235.  
  236.     g.setFont(titleFont);
  237.     i = g.getFontMetrics().stringWidth(title);
  238.     g.drawString((title == null) ? "Spreadsheet" : title,
  239.              (d.width - i) / 2, 12);
  240.     g.setColor(inputColor);
  241.     g.fillRect(0, cellHeight, d.width, cellHeight);
  242.     g.setFont(titleFont);
  243.     for (i=0; i < rows+1; i++) {
  244.         cy = (i+2) * cellHeight;
  245.         g.setColor(getBackground());
  246.         g.draw3DRect(0, cy, d.width, 2, true);
  247.         if (i < rows) {
  248.         g.setColor(Color.red);
  249.         g.drawString("" + (i+1), 2, cy + 12);
  250.         }
  251.     }
  252.  
  253.     g.setColor(Color.red);
  254.     cy = (rows+3) * cellHeight + (cellHeight / 2);
  255.     for (i=0; i < columns; i++) {
  256.         cx = i * cellWidth;
  257.         g.setColor(getBackground());
  258.         g.draw3DRect(cx + rowLabelWidth,
  259.               2 * cellHeight, 1, d.height, true);
  260.         if (i < columns) {
  261.         g.setColor(Color.red);
  262.         l[0] = (char)((int)'A' + i);
  263.         g.drawString(new String(l),
  264.                  cx + rowLabelWidth + (cellWidth / 2),
  265.                  cy);
  266.         }
  267.     }
  268.  
  269.     for (i=0; i < rows; i++) {
  270.         for (j=0; j < columns; j++) {
  271.         cx = (j * cellWidth) + 2 + rowLabelWidth;
  272.         cy = ((i+1) * cellHeight) + 2 + titleHeight;
  273.         if (cells[i][j] != null) {
  274.             cells[i][j].paint(g, cx, cy);
  275.         }
  276.         }
  277.     }
  278.  
  279.     g.setColor(getBackground());
  280.     g.draw3DRect(0, titleHeight,
  281.               d.width,
  282.               d.height - titleHeight,
  283.               false);
  284.     inputArea.paint(g, 1, titleHeight + 1);
  285.     }
  286.  
  287.       //1.1 event handling
  288.       
  289.   public void mouseClicked(MouseEvent e)
  290.   {}
  291.       
  292.   public void mousePressed(MouseEvent e)
  293.   {
  294.     int x = e.getX();
  295.     int y = e.getY();
  296.     Cell cell;
  297.     if (y < (titleHeight + cellHeight)) {
  298.       selectedRow = -1;
  299.       if (y <= titleHeight && current != null) {
  300.     current.deselect();
  301.     current = null;
  302.       }
  303.       e.consume();
  304.     }
  305.     if (x < rowLabelWidth) {
  306.       selectedRow = -1;
  307.       if (current != null) {
  308.     current.deselect();
  309.         current = null;
  310.       }
  311.       e.consume();
  312.       
  313.     }
  314.     selectedRow = ((y - cellHeight - titleHeight) / cellHeight);
  315.     selectedColumn = (x - rowLabelWidth) / cellWidth;
  316.     if (selectedRow > rows ||
  317.     selectedColumn >= columns) {
  318.       selectedRow = -1;
  319.       if (current != null) {
  320.     current.deselect();
  321.     current = null;
  322.       }
  323.     } else {
  324.       if (selectedRow >= rows) {
  325.     selectedRow = -1;
  326.     if (current != null) {
  327.       current.deselect();
  328.       current = null;
  329.     }
  330.     e.consume();
  331.       }
  332.       cell = cells[selectedRow][selectedColumn];
  333.       inputArea.setText(new String(cell.getPrintString()));
  334.       if (current != null) {
  335.     current.deselect();
  336.       }
  337.       current = cell;
  338.       current.select();
  339.       requestFocus();
  340.       fullUpdate = true;
  341.       repaint();
  342.     }
  343.     e.consume();
  344.   }
  345.  
  346.   public void mouseReleased(MouseEvent e) 
  347.   {}
  348.       
  349.   public void mouseEntered(MouseEvent e)
  350.   {}
  351.       
  352.   public void mouseExited(MouseEvent e)     
  353.   {}
  354.  
  355.   public void keyPressed(KeyEvent e)
  356.   {
  357.     fullUpdate=true;
  358.     inputArea.processKey(e);
  359.     e.consume();
  360.   }
  361.   
  362.   public void keyTyped(KeyEvent e) {
  363.   }
  364.   
  365.   public void keyReleased(KeyEvent e)
  366.   {}   
  367.       
  368.   public String getAppletInfo() {
  369.     return "Title: SpreadSheet \nAuthor: Sami Shaio \nA simple spread sheet.";
  370.   }
  371.       
  372.   public String[][] getParameterInfo() {
  373.     String[][] info = {
  374.       {"title", "string", "The title of the spread sheet.  Default is 'Spreadsheet'"},
  375.       {"rows", "int", "The number of rows.  Default is 9."},
  376.       {"columns", "int", "The number of columns.  Default is 5."}
  377.     };
  378.     return info;
  379.   }
  380.  
  381.  
  382. }
  383.  
  384. class CellUpdater extends Thread {
  385.     Cell     target;
  386.     InputStream dataStream = null;
  387.     StreamTokenizer tokenStream;
  388.  
  389.     public CellUpdater(Cell c) {
  390.     super("cell updater");
  391.     target = c;
  392.     }
  393.  
  394.     public void run() {
  395.     try {
  396.         dataStream = new URL(target.app.getDocumentBase(),
  397.                  target.getValueString()).openStream();
  398.         tokenStream = new StreamTokenizer(new BufferedReader(new InputStreamReader(dataStream)));
  399.         tokenStream.eolIsSignificant(false);
  400.         
  401.         while (true) {
  402.         switch (tokenStream.nextToken()) {
  403.         case tokenStream.TT_EOF:
  404.             dataStream.close();
  405.             return;
  406.         default:
  407.             break;
  408.         case tokenStream.TT_NUMBER:
  409.             target.setTransientValue((float)tokenStream.nval);
  410.             if (! target.app.isStopped && ! target.paused) {
  411.             target.app.repaint();
  412.             }
  413.             break;
  414.         }
  415.         try {
  416.             Thread.sleep(2000);
  417.         } catch (InterruptedException e) {
  418.             break;
  419.         }
  420.         }
  421.     } catch (IOException e) {
  422.         return;
  423.     }
  424.     }
  425. }
  426.  
  427. class Cell {
  428.     public static final int VALUE = 0;
  429.     public static final int LABEL = 1;
  430.     public static final int URL   = 2;
  431.     public static final int FORMULA = 3;
  432.     
  433.     Node    parseRoot;
  434.     boolean    needRedisplay;
  435.     boolean selected = false;
  436.     boolean transientValue = false;
  437.     public int    type = Cell.VALUE;
  438.     String    valueString = "";
  439.     String    printString = "v";
  440.     float    value;
  441.     Color    bgColor;
  442.     Color    fgColor;
  443.     Color    highlightColor;
  444.     int        width;
  445.     int        height;
  446.     SpreadSheet app;
  447.     CellUpdater    updaterThread;
  448.     boolean    paused = false;
  449.  
  450.     public Cell(SpreadSheet app,
  451.         Color bgColor,
  452.         Color fgColor,
  453.         Color highlightColor,
  454.         int width,
  455.         int height) {
  456.     this.app = app;
  457.     this.bgColor = bgColor;
  458.     this.fgColor = fgColor;
  459.     this.highlightColor = highlightColor;
  460.     this.width = width;
  461.     this.height = height;
  462.     needRedisplay = true;
  463.     }
  464.         
  465.     public void setRawValue(float f) {
  466.     valueString = Float.toString(f);
  467.     value = f;
  468.     }
  469.     public void setValue(float f) {
  470.     setRawValue(f);
  471.     printString = "v" + valueString;
  472.     type = Cell.VALUE;
  473.     paused = false;
  474.     app.recalculate();
  475.     needRedisplay = true;
  476.     }
  477.  
  478.     public void setTransientValue(float f) {
  479.     transientValue = true;
  480.     value = f;
  481.     needRedisplay = true;
  482.     app.recalculate();
  483.     }
  484.  
  485.     public void setUnparsedValue(String s) {
  486.     switch (s.charAt(0)) {
  487.       case 'v':
  488.         setValue(Cell.VALUE, s.substring(1));
  489.         break;
  490.       case 'f':
  491.         setValue(Cell.FORMULA, s.substring(1));
  492.         break;
  493.       case 'l':
  494.         setValue(Cell.LABEL, s.substring(1));
  495.         break;
  496.       case 'u':
  497.         setValue(Cell.URL, s.substring(1));
  498.         break;
  499.     }
  500.     }
  501.  
  502.     /**
  503.      * Parse a spreadsheet formula. The syntax is defined as:
  504.      *
  505.      * formula -> value
  506.      * formula -> value op value
  507.      * value -> '(' formula ')'
  508.      * value -> cell
  509.      * value -> <number>
  510.      * op -> '+' | '*' | '/' | '-'
  511.      * cell -> <letter><number>
  512.      */
  513.     public String parseFormula(String formula, Node node) {
  514.     String subformula;
  515.     String restFormula;
  516.     float value;
  517.     int length = formula.length();
  518.     Node left;
  519.     Node right;
  520.     char op;
  521.  
  522.     if (formula == null) {
  523.         return null;
  524.     }
  525.     subformula = parseValue(formula, node);
  526.     //System.out.println("subformula = " + subformula);
  527.     if (subformula == null || subformula.length() == 0) {
  528.         //System.out.println("Parse succeeded");
  529.         return null;
  530.     }
  531.     if (subformula == formula) {
  532.         //System.out.println("Parse failed");
  533.         return formula;
  534.     }
  535.  
  536.     // parse an operator and then another value
  537.     switch (op = subformula.charAt(0)) {
  538.       case 0:
  539.         //System.out.println("Parse succeeded");
  540.         return null;
  541.       case ')':
  542.         //System.out.println("Returning subformula=" + subformula);
  543.         return subformula;
  544.       case '+':
  545.       case '*':
  546.       case '-':
  547.       case '/':
  548.         restFormula = subformula.substring(1);
  549.         subformula = parseValue(restFormula, right=new Node());
  550.         //System.out.println("subformula(2) = " + subformula);
  551.         if (subformula != restFormula) {
  552.         //System.out.println("Parse succeeded");
  553.         left = new Node(node);
  554.         node.left = left;
  555.         node.right = right;
  556.         node.op = op;
  557.         node.type = Node.OP;
  558.         //node.print(3);
  559.         return subformula;
  560.         } else {
  561.         //System.out.println("Parse failed");
  562.         return formula;
  563.         }
  564.       default:
  565.         //System.out.println("Parse failed (bad operator): " + subformula);
  566.         return formula;
  567.     }
  568.     }
  569.  
  570.     public String parseValue(String formula, Node node) {
  571.     char    c = formula.charAt(0);
  572.     String    subformula;
  573.     String    restFormula;
  574.     float    value;
  575.     int    row;
  576.     int    column;
  577.  
  578.     //System.out.println("parseValue: " + formula);
  579.     restFormula = formula;
  580.     if (c == '(') {
  581.         //System.out.println("parseValue(" + formula + ")");
  582.         restFormula = formula.substring(1);
  583.         subformula = parseFormula(restFormula, node);
  584.         //System.out.println("rest=(" + subformula + ")");
  585.         if (subformula == null ||
  586.         subformula.length() == restFormula.length()) {
  587.         //System.out.println("Failed");
  588.         return formula;
  589.         } else if (! (subformula.charAt(0) == ')')) {
  590.             //System.out.println("Failed (missing parentheses)");
  591.         return formula;
  592.         }
  593.         restFormula = subformula;
  594.     } else if (c >= '0' && c <= '9') {
  595.         int i;
  596.  
  597.         //System.out.println("formula=" + formula);
  598.         for (i=0; i < formula.length(); i++) {
  599.         c = formula.charAt(i);
  600.         if ((c < '0' || c > '9') && c != '.') {
  601.             break;
  602.         }
  603.         }
  604.         try {
  605.         value = Float.valueOf(formula.substring(0, i)).floatValue();
  606.         } catch (NumberFormatException e) {
  607.         //System.out.println("Failed (number format error)");
  608.         return formula;
  609.         }
  610.         node.type = Node.VALUE;
  611.         node.value = value;
  612.         //node.print(3);
  613.         restFormula = formula.substring(i);
  614.         //System.out.println("value= " + value + " i=" + i +
  615.         //               " rest = " + restFormula);
  616.         return restFormula;
  617.     } else if (c >= 'A' && c <= 'Z') {
  618.         int i;
  619.  
  620.         column = c - 'A';
  621.         restFormula = formula.substring(1);
  622.         for (i=0; i < restFormula.length(); i++) {
  623.         c = restFormula.charAt(i);
  624.         if (c < '0' || c > '9') {
  625.             break;
  626.         }
  627.         }
  628.         row = Float.valueOf(restFormula.substring(0, i)).intValue();
  629.         //System.out.println("row = " + row + " column = " + column);
  630.         node.row = row - 1;
  631.         node.column = column;
  632.         node.type = Node.CELL;
  633.         //node.print(3);
  634.         if (i == restFormula.length()) {
  635.         restFormula = null;
  636.         } else {
  637.         restFormula = restFormula.substring(i);
  638.         if (restFormula.charAt(0) == 0) {
  639.             return null;
  640.         }
  641.         }        
  642.     }
  643.  
  644.     return restFormula;
  645.     }
  646.  
  647.  
  648.     public void setValue(int type, String s) {
  649.     paused = false;
  650.     if (this.type == Cell.URL) {
  651.         updaterThread.stop();
  652.         updaterThread = null;
  653.     }
  654.  
  655.     valueString = new String(s);
  656.     this.type = type;
  657.     needRedisplay = true;
  658.     switch (type) {
  659.       case Cell.VALUE:
  660.         setValue(Float.valueOf(s).floatValue());
  661.         break;
  662.       case Cell.LABEL:
  663.         printString = "l" + valueString;
  664.         break;
  665.       case Cell.URL:
  666.         printString = "u" + valueString;
  667.         updaterThread = new CellUpdater(this);
  668.         updaterThread.start();
  669.         break;
  670.       case Cell.FORMULA:
  671.         parseFormula(valueString, parseRoot = new Node());
  672.         printString = "f" + valueString;
  673.         break;
  674.     }
  675.     app.recalculate();
  676.     }
  677.  
  678.     public String getValueString() {
  679.     return valueString;
  680.     }
  681.  
  682.     public String getPrintString() {
  683.     return printString;
  684.     }
  685.  
  686.     public void select() {
  687.     selected = true;
  688.     paused = true;
  689.     }
  690.     public void deselect() {
  691.     selected = false;
  692.     paused = false;
  693.     needRedisplay = true;
  694.     app.repaint();
  695.     }
  696.     public void paint(Graphics g, int x, int y) {
  697.     if (selected) {
  698.         g.setColor(highlightColor);
  699.     } else {
  700.         g.setColor(bgColor);
  701.     }
  702.     g.fillRect(x, y, width - 1, height);
  703.     if (valueString != null) {
  704.         switch (type) {
  705.           case Cell.VALUE:
  706.           case Cell.LABEL:
  707.         g.setColor(fgColor);
  708.         break;
  709.           case Cell.FORMULA:
  710.         g.setColor(Color.red);
  711.         break;
  712.           case Cell.URL:
  713.         g.setColor(Color.blue);
  714.         break;
  715.         }
  716.         if (transientValue){
  717.         g.drawString("" + value, x, y + (height / 2) + 5);
  718.         } else {
  719.         if (valueString.length() > 14) {
  720.             g.drawString(valueString.substring(0, 14),
  721.                  x, y + (height / 2) + 5);
  722.         } else {
  723.             g.drawString(valueString, x, y + (height / 2) + 5);
  724.         }
  725.         }
  726.     }
  727.     needRedisplay = false;
  728.     }
  729. }
  730.  
  731. class Node {
  732.     public static final int OP = 0;
  733.     public static final    int VALUE = 1;
  734.     public static final int CELL = 2;
  735.  
  736.     int        type;
  737.     Node     left;
  738.     Node     right;
  739.     int      row;
  740.     int      column;
  741.     float    value;
  742.     char    op;
  743.  
  744.     public Node() {
  745.     left = null;
  746.     right = null;
  747.     value = 0;
  748.     row = -1;
  749.     column = -1;
  750.     op = 0;
  751.     type = Node.VALUE;
  752.     }
  753.     public Node(Node n) {
  754.     left = n.left;
  755.     right = n.right;
  756.     value = n.value;
  757.     row = n.row;
  758.     column = n.column;
  759.     op = n.op;
  760.     type = n.type;
  761.     }
  762.     public void indent(int ind) {
  763.     for (int i = 0; i < ind; i++) {
  764.         System.out.print(" ");
  765.     }
  766.     }
  767.     public void print(int indentLevel) {
  768.     char l[] = new char[1];
  769.     indent(indentLevel);
  770.     System.out.println("NODE type=" + type);
  771.     indent(indentLevel);
  772.     switch (type) {
  773.       case Node.VALUE:
  774.         System.out.println(" value=" + value);
  775.         break;
  776.       case Node.CELL:
  777.         l[0] = (char)((int)'A' + column);
  778.         System.out.println(" cell=" + new String(l) + (row+1));
  779.         break;
  780.       case Node.OP:
  781.         System.out.println(" op=" + op);
  782.         left.print(indentLevel + 3);
  783.         right.print(indentLevel + 3);
  784.         break;
  785.     }
  786.     }
  787. }
  788.  
  789. class InputField {
  790.     int        maxchars = 50;
  791.     int        cursorPos = 0;
  792.     Applet    app;
  793.     String    sval;
  794.     char    buffer[];
  795.     int        nChars;
  796.     int        width;
  797.     int        height;
  798.     Color    bgColor;
  799.     Color    fgColor;
  800.  
  801.     public InputField(String initValue, Applet app, int width, int height,
  802.               Color bgColor, Color fgColor) {
  803.     this.width = width;
  804.     this.height = height;
  805.     this.bgColor = bgColor;
  806.     this.fgColor = fgColor;
  807.     this.app = app;
  808.     buffer = new char[maxchars];
  809.     nChars = 0;
  810.     if (initValue != null) {
  811.         initValue.getChars(0, initValue.length(), this.buffer, 0);
  812.         nChars = initValue.length();
  813.     }
  814.     sval = initValue;
  815.     }
  816.  
  817.     public void setText(String val) {
  818.     int i;
  819.  
  820.     for (i=0; i < maxchars; i++) {
  821.         buffer[i] = 0;
  822.     }
  823.     sval = new String(val);
  824.     if (val == null) {
  825.         sval = "";
  826.         nChars = 0;
  827.         buffer[0] = 0;
  828.     } else {
  829.         sval.getChars(0, sval.length(), buffer, 0);
  830.         nChars = val.length();
  831.         sval = new String(buffer);
  832.     }
  833.     }
  834.  
  835.     public String getValue() {
  836.     return sval;
  837.     }
  838.  
  839.     public void paint(Graphics g, int x, int y) {
  840.     g.setColor(bgColor);
  841.     g.fillRect(x, y, width, height);
  842.     if (sval != null) {
  843.         g.setColor(fgColor);
  844.         g.drawString(sval, x, y + (height / 2) + 3);
  845.     }
  846.     }
  847.  
  848.   public void processKey(KeyEvent e) {
  849.     int key = e.getKeyCode();
  850.     if (nChars < maxchars) {
  851.       switch (key) {
  852.       case 8: // delete
  853.     --nChars;
  854.     if (nChars < 0) {
  855.       nChars = 0;
  856.     }
  857.     buffer[nChars] = 0;
  858.     sval = new String(new String(buffer));
  859.     break;
  860.       case 10: // return
  861.     selected();
  862.     break;
  863.       default:
  864.     if (key >= 48) { //the number 0 in the ASCII char range
  865.       buffer[nChars++] = e.getKeyChar();
  866.       sval = new String(new String(buffer));
  867.     }
  868.     break;
  869.       }
  870.     }
  871.     app.repaint();    
  872.   }
  873.   
  874.   public void keyReleased(KeyEvent e) {
  875.   }      
  876.   
  877.   public void selected() {
  878.   }
  879. }
  880.  
  881. class SpreadSheetInput 
  882.     extends InputField {
  883.     
  884.   public SpreadSheetInput(String initValue,
  885.               SpreadSheet app,
  886.               int width,
  887.               int height,
  888.               Color bgColor,
  889.               Color fgColor) {
  890.     super(initValue, app, width, height, bgColor, fgColor);
  891.   }
  892.       
  893.     public void selected() {
  894.     float f;
  895.  
  896.     switch (sval.charAt(0)) {
  897.       case 'v':
  898.           String s= sval.substring(1);
  899.         try {
  900.         int i;
  901.         for (i = 0; i < s.length(); i++) {
  902.             char c = s.charAt(i);
  903.             if (c < '0' || c > '9')
  904.             break;
  905.         }
  906.         s = s.substring(0, i);
  907.         f = Float.valueOf(s).floatValue();
  908.         ((SpreadSheet)app).setCurrentValue(f);
  909.         } catch (NumberFormatException e) {
  910.         System.out.println("Not a float: '" + s + "'");
  911.         }
  912.         break;
  913.       case 'l':
  914.         ((SpreadSheet)app).setCurrentValue(Cell.LABEL, sval.substring(1));
  915.         break;
  916.       case 'u':
  917.         ((SpreadSheet)app).setCurrentValue(Cell.URL, sval.substring(1));
  918.         break;
  919.       case 'f':
  920.         ((SpreadSheet)app).setCurrentValue(Cell.FORMULA, sval.substring(1));
  921.         break;
  922.     }
  923.     }
  924. }
  925.